use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
use crate::get_constant_info_from_vm_class;
use crate::instruction::instruction::Instruction;
use crate::class::vm_access_flags::{is_final, is_static};
use crate::class::vm_class::VMClass;
use crate::class::vm_class_constant_info::VMClassConstantInfoEnum;
use crate::vm_thread::{VMFrame, VMThread};
use crate::vm_val::{NULL_REF, VMValEnum};

pub struct getstatic {
    pub index: u16,
}

impl Instruction for getstatic {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.index = frame.borrow_mut().read_u16();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let mut field_ref = {
            let ro_frame = frame.borrow();
            get_constant_info_from_vm_class!(ro_frame.current_vm_class, self.index, VMClassConstantInfoFieldRef)
        };

        field_ref.init(thread);

        let field = field_ref.vm_class_field.clone().unwrap();
        let ro_field = field.borrow();
        if !is_static(ro_field.access_flags) {
            panic!("非静态变量，不允许执行此指令")
        }

        let vm_class = field_ref.vm_class.clone().unwrap();
        if !vm_class.has_init() {
            VMClass::init(vm_class, frame, thread);
            return;
        }
        let mut statis_slot = vm_class.static_slot.borrow_mut();
        let val_option = statis_slot.get(&ro_field.slot_id);

        let rw_frame = frame.deref().borrow_mut();
        let mut operand_stack = rw_frame.operand_stack.borrow_mut();
        if val_option.is_none() {
            operand_stack.push(VMValEnum::VMValRef { val: NULL_REF });
        } else {
            let val = val_option.unwrap().clone();
            operand_stack.push(val);
        }
    }

    fn to_string(&self) -> String {
        String::from("getstatic")
    }
}